<?php 
/**
 * Service_Sitemap
 * 
 * Класс обеспечивает генерацию файлов sitemap
 *
 * @author Дмитрий Кузьма <kouzma.d@gmail.com>
 * @version 1.0
 */

class Service_Sitemap {


	protected $objSitemapFile = null;
	protected $objSitemapHotelsFile = null;
	protected $objRobotsFile = null;
	public static $nrHotelsLimitForMultySitemap = 8000;
	
	protected $citiesSitemaped = 0;
	protected $stopSitemapping = false;
	
	/**
	 * Генерирует файл robots.txt
	 */
	public function generateRobotsTxt() {
		Service_Debug::setDebug();
		Service_Debug::$handDebugOff = true;
		$this->objRobotsFile = fopen(ABSPATH . 'robots.txt', 'w');
		if ($this->objRobotsFile === false) return false;
		if (DOMAIN == 'hotels.ru') {
			$strRobots = "User-agent: *\n";
			$strRobots .= "Disallow: /auth/*\n";
			$strRobots .= "Allow: /\n";
			$strRobots .= "Crawl-delay: 1\n";      // Задержка между загрузкой двух страниц
			$strRobots .= "Request-rate: 1\n";     // Загружать не более одной страницы за 1 секунду
			$strRobotsDomain = "Host: www." . DOMAIN . "\n";
			//$strRobots .= "Visit-time: 0600-0845\n"; // Загружать страницы только в промежуток с 6 утра
			$strRobots .= "Sitemap: " . W_FULLPATH . "content/sitemap/sitemap.xml\n"; // Sitemap
		}
		else {
			$strRobots = "Disallow: *\n";
		}
		fwrite($this->objRobotsFile, $strRobots);
    //fwrite($this->objRobotsFile, );
    if (DOMAIN == 'hotels.ru') fwrite($this->objRobotsFile, $strRobotsDomain);
    //$this->fillRobotsSitemaps();
		fclose($this->objRobotsFile);
	}
	
	/**
	 * Заполняет в главный sitemap ссылки на sitemaps
	 * 
	 */
	public function fillMainSitemap() {
		Service_Debug::setDebug();
		$dir = ABSPATH . "/content/sitemap/";   // Имя директории
    if (is_dir($dir)) {   // Проверяем наличие директории
			$files = scandir($dir); // Получаем массив файлов
			array_shift($files); // удаляем из массива '.'	
			array_shift($files); // удаляем из массива '..'
			for($i = 0; $i < sizeof($files); $i++) {
				if ($files[$i] == 'sitemap.xml') continue;  
				$file = W_FULLPATH . "content/sitemap/" . $files[$i];
   			fwrite($this->objSitemapFile, "<sitemap>\n");
   			fwrite($this->objSitemapFile, '<loc>' . $file . "</loc>\n");
   			fwrite($this->objSitemapFile, "<lastmod>" . Service_Date::changeDateFormat(filemtime(ABSPATH . "content/sitemap/" . $files[$i]), 'U', 'Y-m-d') . "</lastmod>\n");
   			fwrite($this->objSitemapFile, "</sitemap>\n");
			}
    }
	}
	
	/**
	 * Заполняет в robots.txt ссылки на sitemaps и создает эти sitemaps 
	 * 
	 */
	public function fillRobotsSitemaps() {
		Service_Debug::setDebug();
		
		// Генерируем по странам
		$obCountry = new Country();
		$arrCountries = $obCountry->find('all', array('select' => '`country_url`, `nr_hotels`, `country_code`', 'order' => '`country_code` ASC'));
		if ($arrCountries) {
			foreach ($arrCountries as $arrCountry) {
				fwrite($this->objRobotsFile, 'Sitemap: ' . W_FULLPATH . 'content/sitemap/' . $arrCountry['country_code'] . ".xml\n");
				$this->generateCountrySitemap($arrCountry);
			}
  	}
  	
  	// Генерируем по статьям
  	fwrite($this->objRobotsFile, 'Sitemap: ' . W_FULLPATH . "content/sitemap/articles.xml\n");
  	$this->generateArticlesSitemap();
  	
  	// Генерируем по достопримечательностям
  	fwrite($this->objRobotsFile, 'Sitemap: ' . W_FULLPATH . "content/sitemap/places.xml\n");
  	$this->generatePlacesSitemap();
	}

	
	/**
	 * Генерирует sitemap
	 */
	public function generateSitemap() {
		Service_Debug::setDebug();
		$this->generateArticlesSitemap(); // Генерируем по статьям
		$this->generatePlacesSitemap(); // Генерируем по статьям
		// Генерируем по странам
		$obCountry = new Country();
		$arrCountries = $obCountry->find('all', array('select' => '`country_url`, `nr_hotels`, `country_code`', 'order' => '`sitemap_generated` ASC, `country_code` ASC'));
		if ($arrCountries) {
			foreach ($arrCountries as $arrCountry) {
				$this->generateCountrySitemap($arrCountry, 'rus');
				$this->generateCountrySitemap($arrCountry, 'eng');
				if ($this->citiesSitemaped > 3000) break;
			}
  	}
	}
	
	/**
	 * Генерирует sitemap
	 */
	public function generateSitemapOld() {
		Service_Debug::setDebug();
		$this->objSitemapFile = fopen(ABSPATH . 'sitemap.xml', 'w');
		if ($this->objSitemapFile === false) return false;
		fwrite($this->objSitemapFile, $this->getSitemapOpen());
		$this->fillAllUrls();
		fwrite($this->objSitemapFile, $this->getSitemapClose());
		fclose($this->objSitemapFile);
	}
	
	/**
	 * 
	 * Открывает sitemap
	 */
	public function getSitemapOpen() {
		Service_Debug::setDebug();
		return '<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
	}
	
	/**
	 * 
	 * Закрывает sitemap
	 */
	public function getSitemapClose() {
		Service_Debug::setDebug();
		return '</urlset>';
	}
	
	/**
	 * Получает блок sitemap для одного url
	 * 
	 * @param string $url - ссылка
	 * @param string $lastMod - дата последнего редактирования файла
	 * @param string $changeFreq - частота обновления (always/hourly/daily/weekly/monthly/yearly/never)
	 * @param string $priority - приоритет страницы
	 */
	public function getUrl($url, $lastMod = null, $changeFreq = null, $priority = '0.5') {
		Service_Debug::setDebug();
		if ($url == '#') return '';
		$retStr = "<url>\n";
		  $retStr .= '<loc>' . Service_Escape::absolutelyEscapeString($url) . "</loc>\n";
		  if($lastMod) $retStr .= '<lastmod>' . $lastMod . "</lastmod>\n";
		  if($changeFreq) $retStr .= '<changefreq>' . $changeFreq . "</changefreq>\n";
		  if($priority) $retStr .= '<priority>' . $priority . "</priority>\n";
		$retStr .= "</url>\n";
		return $retStr;
	}

/*====================================================*/
/* Настройки конкретного сайта */
/*====================================================*/
	public function fillAllUrls() {
		Service_Debug::setDebug();
		fwrite($this->objSitemapFile, '');
	}
	
	/**
	 * Генерирует sitemap для конкретной страны
	 * 
	 * @param array $arrCountry - массив с информацией по стране
	 */
	public function generateCountrySitemap($arrCountry, $urlLang = 'rus') {
		Service_Debug::setDebug();
		if (!$arrCountry) return false;
		$objCity = new City();
		$citiesAmount = $objCity->count("`city`.`country_code` = '" . $arrCountry['country_code'] . "'");
		$this->citiesSitemaped += $citiesAmount;
		$this->objSitemapFile = fopen(ABSPATH . 'content/sitemap/' . $arrCountry['country_code'] . '.' . substr($urlLang, 0, 2) . '.xml', 'w');
		if ($arrCountry['nr_hotels'] >= self::$nrHotelsLimitForMultySitemap) {
			$this->objSitemapHotelsFile = fopen(ABSPATH . 'content/sitemap/' . $arrCountry['country_code'] . '.' . substr($urlLang, 0, 2) . '.hotel.xml', 'w');
			if ($this->objSitemapHotelsFile === false) return false;
			fwrite($this->objSitemapHotelsFile, $this->getSitemapOpen());
		}
		if ($this->objSitemapFile === false) return false;
		// Создаем sitemap где города по стране
		fwrite($this->objSitemapFile, $this->getSitemapOpen());		  
	  $strCountrySitemap = $this->getUrl(View_Country::getUrl($arrCountry, true, false, $urlLang), null, null, '0.8');
		fwrite($this->objSitemapFile, $strCountrySitemap);
		$this->fillCountryCitiesSitemap($arrCountry, $urlLang);
		fwrite($this->objSitemapFile, $this->getSitemapClose());
		fclose($this->objSitemapFile);
		
		// Создаем sitemap где старые города по стране
		$this->fillOldCountryCitiesSitemap($arrCountry, $urlLang);

			
		if ($arrCountry['nr_hotels'] >= self::$nrHotelsLimitForMultySitemap) {
			fwrite($this->objSitemapHotelsFile, $this->getSitemapClose());
			fclose($this->objSitemapHotelsFile);	
		}
		$objCountry = new Country($arrCountry['country_code']);
		$objCountry->updateField('sitemap_generated', Service_Date::gLocalTime2BD());
		
	}
	
	/**
	 * Заполняет карту сайта городами страны
	 * 
	 * @param array $arrCountry
	 */
	public function fillCountryCitiesSitemap($arrCountry, $urlLang = 'rus') {
		Service_Debug::setDebug();
		$objCity = new City();
		$arrCities = $objCity->find('all', array('select' => '`ID_city`, `country_url`, `nr_hotels`, `city_url`', 'conditions' => "`country_code` = '" . $arrCountry['country_code'] . "'"));
		if (!$arrCities) return null;
		$sitemapStr = '';
		$objCurCity = new City();
		foreach ($arrCities as $arrCity) {
			$objCurCity->id = $arrCity['ID_city'];
			$hostelsCnt = $objCurCity->getHostelsCnt();
			$miniCnt = $objCurCity->getMiniHotelsCnt();
			$apartmentsCnt = $objCurCity->getHotelsApartments();
			$sitemapStr .= $this->getUrl(View_City::getUrl($arrCity, true, false, $urlLang), null, null, '0.6');
			$sitemapStr .= $this->getUrl(View_City::getUrlAllHotels($arrCity, true, false, $urlLang), null, null, '0.3');
			if ($hostelsCnt >= 3) {
				$sitemapStr .= $this->getUrl(View_City::getUrlHostels($arrCity, true, false, $urlLang), null, null, '0.5');
			}
			if ($miniCnt >= 3) {
				$sitemapStr .= $this->getUrl(View_City::getUrlMini($arrCity, true, false, $urlLang), null, null, '0.5');
			}
			if ($apartmentsCnt >= 3) {
				$sitemapStr .= $this->getUrl(View_City::getUrlApartments($arrCity, true, false, $urlLang), null, null, '0.5');
			}
			for ($i = 3; $i <= 5; $i++) {
				$starsCnt = $objCurCity->getHotelsCntByStars($i);
				if ($starsCnt >= 3) {
					$sitemapStr .= $this->getUrl(View_City::getUrlHotelsByStars($arrCity, $i, true, false, $urlLang), null, null, '0.5');
				}
			}
			if ($arrCity['nr_hotels'] >= 10) {
				$sitemapStr .= $this->getUrl(View_City::getUrlCheapHotels($arrCity, true, false, $urlLang), null, null, '0.5');
			}
		}
		fwrite($this->objSitemapFile, $sitemapStr);
		$this->fillCountryHotelsSitemap($arrCountry, $urlLang);
	}
	
	/**
	 * Заполняет карту сайта городами страны из старой админки
	 * 
	 * @param array $arrCountry
	 */
	public function fillOldCountryCitiesSitemap($arrCountry, $urlLang = 'rus') {
		Service_Debug::setDebug();
		$objDB = Service_Database::instance();
		$stmt = "SELECT `workname`
						 FROM `cities`
						 WHERE `ian_country_code` = '" . $arrCountry['country_code'] . "'";
		$arrCityUrls = $objDB->selectSimpleArray($stmt);
		if (!$arrCityUrls) return null;
		
		$this->objSitemapFile = fopen(ABSPATH . 'content/sitemap/' . $arrCountry['country_code'] . '.old.' . substr($urlLang, 0, 2) . '.xml', 'w');
		fwrite($this->objSitemapFile, $this->getSitemapOpen());
		$sitemapStr = '';
		foreach ($arrCityUrls as $arrCityUrl) {
			$url = View_City::getOldUrl($arrCountry['country_url'], $arrCityUrl, true);
			$sitemapStr .= $this->getUrl(View_Base::getLanguageUrl($url, true, false, $urlLang), null, null, '0.6');
		}
		fwrite($this->objSitemapFile, $sitemapStr);
		$this->fillCountryOldHotelsSitemap($arrCountry, $urlLang);
		fwrite($this->objSitemapFile, $this->getSitemapClose());
		fclose($this->objSitemapFile);
	}
	
	
	/**
	 * Заполняет карту сайта отелями
	 * 
	 * @param array $arrCountry
	 */
	public function fillCountryHotelsSitemap($arrCountry, $urlLang = 'rus') {
		Service_Debug::setDebug();
		$objHotel = new Hotel();
		$arrHotels = $objHotel->find('all', array('select' => '`country_url`, `city_url`, `hotel_url`', 'conditions' => "`country_code` = '" . $arrCountry['country_code'] . "'"));
		if (!$arrHotels) return null;
		$sitemapStr = '';
		foreach ($arrHotels as $arrHotel) {
			$url = View_Hotel::getUrl($arrHotel, true, false, $urlLang);
			if ($url != '#') $sitemapStr .= $this->getUrl($url, null, null, '0.4');
		}
		if ($arrCountry['nr_hotels'] >= self::$nrHotelsLimitForMultySitemap) {
			fwrite($this->objSitemapHotelsFile, $sitemapStr); 
		}
		else fwrite($this->objSitemapFile, $sitemapStr);
	}	
	
	/**
	 * Заполняет карту сайта отелями из старой админки
	 * 
	 * @param array $arrCountry
	 */
	public function fillCountryOldHotelsSitemap($arrCountry, $urlLang = 'rus') {
		Service_Debug::setDebug();
		$objDB = Service_Database::instance();
		$stmt = "SELECT `cities`.`workname` AS 'city_url', `hotels`.`workname` AS 'hotel_url'
						 FROM `cities`
						 LEFT JOIN `hotels` ON `hotels`.`basic_country_id` = `cities`.`basic_country_id` AND `hotels`.`basic_city_id` = `cities`.`basic_city_id`
						 WHERE `cities`.`ian_country_code` = '" . $arrCountry['country_code'] . "'";
		$arrHotels = $objDB->select($stmt);
		if (!$arrHotels) return null;
		$sitemapStr = '';
		foreach ($arrHotels as $arrHotel) {
			$arrHotel['country_url'] = $arrCountry['country_url'];
			$url = View_Hotel::getUrl($arrHotel, true, false, $urlLang);
			$sitemapStr .= $this->getUrl($url, null, null, '0.4');
		}
		fwrite($this->objSitemapFile, $sitemapStr);
	}

	
	/**
	 * Генерирует sitemap для статей
	 * 
	 */
	public function generateArticlesSitemap() {
		Service_Debug::setDebug();
		$this->objSitemapFile = fopen(ABSPATH . 'content/sitemap/articles.xml', 'w');
		if ($this->objSitemapFile === false) return false;
		fwrite($this->objSitemapFile, $this->getSitemapOpen());
		
		$objArticle = new Article();
  	$arrArticles = $objArticle->find('all', array('select' => 'url'));
		  
  	$sitemapStr = '';
		foreach ($arrArticles as $arrArticle) {
			$url = W_FULLPATH . $arrArticle['url'];
			$sitemapStr .= $this->getUrl(View_Base::getLanguageUrl($url, true, false, 'rus'), null, null, '0.4');
			$sitemapStr .= $this->getUrl(View_Base::getLanguageUrl($url, true, false, 'eng'), null, null, '0.4');
		}
		fwrite($this->objSitemapFile, $sitemapStr);
			
		fwrite($this->objSitemapFile, $this->getSitemapClose());
		fclose($this->objSitemapFile);
	}
	
	/**
	 * Генерирует sitemap для заданного федерального округа
	 *
	 */
	public function generateFederalDistrictSitemap($federalDistrictId) {
		Service_Debug::setDebug();
		
		$objFederalDistrict = new FederalDistrict();
		$citiesArray = $objFederalDistrict->find('all', array('select' => '`city`.`city_url`,`city`.`city_type`,`federal_district`.`federal_district_url`','joins' => ' INNER JOIN `city` USING(`ID_federal_district`)','conditions' => "`city`.`ID_federal_district`='" . $federalDistrictId . "' AND `city`.`importance_level` >='" . City::$minImortanceToView . "'", 'order' => '`city`.`city_type` DESC'));
		
		$objRoute = new Route();
		$routesArray = $objRoute->find('all',array('select' => '`c1`.`city_url` as `one_city_url`,`c2`.`city_url` as `another_city_url`,`c1`.`city_type` as `one_city_type`,`c2`.`city_type` as `another_city_type`', 'joins' => 'INNER JOIN `city` `c1` ON `c1`.`ID_city`=`route`.`ID_one_city` INNER JOIN `city` `c2` ON `c2`.`ID_city`=`route`.`ID_another_city`', 'conditions' => "`c1`.`ID_federal_district`='" . $federalDistrictId . "' AND `c2`.`ID_federal_district`='" . $federalDistrictId . "' AND `c1`.`importance_level` >='" . City::$minImortanceToView . "' AND `c2`.`importance_level` >='" . City::$minImortanceToView . "'"));
		
		$this->objSitemapFile = fopen(ABSPATH . 'content/sitemap/' . $citiesArray[0]['federal_district_url'] . '.xml', 'w');
		if ($this->objSitemapFile === false) return false;
		fwrite($this->objSitemapFile, $this->getSitemapOpen());
		
		$sitemapStr = '';
		// Перебираем города
		$i = 0;
		$j = 0;
		foreach ($citiesArray as $cityArray) {
			$url = W_FULLPATH .  $cityArray['federal_district_url'] . '/' . $cityArray['city_url'];
			
			if($cityArray['city_type'] == 5 || $cityArray['city_type'] == 6) $priority = '0.7';
			elseif($cityArray['city_type'] == 3 || $cityArray['city_type'] == 4) $priority = '0.6';
			elseif($cityArray['city_type'] == 1 || $cityArray['city_type'] == 2) $priority = '0.5';
			else $priority = '0.4';
			$i++;
			$sitemapStr .= $this->getUrl($url, null, null, $priority);
		}
	
		// Перебираем маршруты
		foreach ($routesArray as $routeArray) {
			if($routeArray['one_city_type'] > $routeArray['another_city_type'] || ($routeArray['one_city_type'] == $routeArray['another_city_type'] && $routeArray['one_city_url'] < $routeArray['another_city_url'])) $url = W_FULLPATH . 'routes/' . $routeArray['one_city_url'] . '-' . $routeArray['another_city_url'];
			else $url = W_FULLPATH . 'routes/' . $routeArray['another_city_url'] . '-' . $routeArray['one_city_url'];  
			
			$sum = $routeArray['one_city_type'] + $routeArray['another_city_type'];
			if($sum < 3) $priority = '0.2';
			elseif($sum < 6) $priority = '0.3';
			elseif($sum < 9) $priority = '0.4';
			else $priority = '0.5';
			$j++;
			$sitemapStr .= $this->getUrl($url, null, null, $priority);
		}
		echo $i . ' городов';
		echo $j . ' маршрутов';
		fwrite($this->objSitemapFile, $sitemapStr);
			
		fwrite($this->objSitemapFile, $this->getSitemapClose());
		fclose($this->objSitemapFile);
	}

	
	/**
	 * Генерирует sitemap для достопримечательностей
	 * 
	 */
	public function generatePlacesSitemap() {
		Service_Debug::setDebug();
		$this->objSitemapFile = fopen(ABSPATH . 'content/sitemap/places.xml', 'w');
		if ($this->objSitemapFile === false) return false;
		fwrite($this->objSitemapFile, $this->getSitemapOpen());
		
		$objPlace = new Place();
  	$arrPlaces = $objPlace->find('all', array('select' => '`url`, `country_url`, `city_url`'));
  	$arrCitiesWithPlaces = $objPlace->find('all', array(
  		'select' => 'DISTINCT `city`.`ID_city`,`city`.`city_url`, `city`.`country_url`',
  		'joins' => 'INNER JOIN `city` USING(`ID_city`)'
  	));
  	$arrCountriesWithPlaces = $objPlace->find('all', array(
  		'select' => 'DISTINCT `country`.`country_code`, `country`.`country_url`',
  		'joins' => 'INNER JOIN `country` USING(`country_code`)'
  	));
		  
  	// Запись в файл списка достопримечательностей
  	$sitemapStr = '';
		foreach ($arrPlaces as $arrPlace) {
			$url = View_Place::getUrl($arrPlace, true);
			$sitemapStr .= $this->getUrl(View_Base::getLanguageUrl($url, true, false, 'rus'), null, null, '0.2');
			$sitemapStr .= $this->getUrl(View_Base::getLanguageUrl($url, true, false, 'eng'), null, null, '0.2');
		}
		fwrite($this->objSitemapFile, $sitemapStr);
		
		// Запись в файл списка городов с достопримечательностями
		$sitemapStr = '';
		foreach ($arrCitiesWithPlaces as $arrCity) {
			$url = View_Place::getCityUrl($arrCity, true);
			$sitemapStr .= $this->getUrl(View_Base::getLanguageUrl($url, true, false, 'rus'), null, null, '0.3');
			$sitemapStr .= $this->getUrl(View_Base::getLanguageUrl($url, true, false, 'eng'), null, null, '0.3');
		}
		fwrite($this->objSitemapFile, $sitemapStr);
		
		// Запись списка стран с достопримечательностями
		$sitemapStr = '';
		foreach ($arrCountriesWithPlaces as $arrCountry) {
			$url = View_Place::getCountryUrl($arrCountry, true);
			$sitemapStr .= $this->getUrl(View_Base::getLanguageUrl($url, true, false, 'rus'), null, null, '0.3');
			$sitemapStr .= $this->getUrl(View_Base::getLanguageUrl($url, true, false, 'eng'), null, null, '0.3');
		}
		fwrite($this->objSitemapFile, $sitemapStr);
			
		fwrite($this->objSitemapFile, $this->getSitemapClose());
		fclose($this->objSitemapFile);
	}
	
	/**
	 * Генерирует главный sitemap с другими SiteMap 
	 * 
	 */
	public function generateMainSitemap() {
		Service_Debug::setDebug();
		$this->objSitemapFile = fopen(ABSPATH . 'content/sitemap/sitemap.xml', 'w');
		if ($this->objSitemapFile === false) return false;
		fwrite($this->objSitemapFile, '<?xml version="1.0" encoding="UTF-8"?><sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');

		$this->fillMainSitemap();
			
		fwrite($this->objSitemapFile, '</sitemapindex>');
		fclose($this->objSitemapFile);
	}
	
  	
}
?>